#pragma once
#include<string>
#include<map>
#include<iostream>
#include<fstream>
#include<mutex>
#include<algorithm>
#include<vector>
namespace cmg{
    using namespace std;
    extern std::mutex myMutex;
    vector<string> splitWithStl(const string str, const string part);
    struct Feature{
            Feature(unsigned int fid,
            string fileName,
            string fileType){
                this->fid=fid;
                this->fileName=fileName;
                this->fileType=fileType;
                macroDefine=0;
                typeDecl=0;
                typeDef=0;
                localSymbolDecl=0;
                localSymbolDef=0;
                typeNameDecl=0;
                funcDecl=0;
                funcDef=0;
                staticFuncDecl=0;
                staticFuncDef=0;
                inlineFuncDecl=0;
                inlineFuncDef=0;
                globalVarDecl=0;
                globalVarDef=0;
                globalStaticVarDef=0;
                templateTypeDecl=0;
                templateTypeDef=0;
                templateFuncDecl=0;
                templateFuncDef=0;
            }
           
           
           void FeatureAdd(const Feature& feature){
                macroDefine+=feature.macroDefine;
                typeDecl+=feature.typeDecl;
                typeDef+=feature.typeDef;
                localSymbolDecl+=feature.localSymbolDecl;
                localSymbolDef+=feature.localSymbolDef;
                typeNameDecl+=feature.typeNameDecl;
                funcDecl+=feature.funcDecl;
                funcDef+=feature.funcDef;
                staticFuncDecl+=feature.staticFuncDecl;
                staticFuncDef+=feature.staticFuncDef;
                inlineFuncDecl+=feature.inlineFuncDecl;
                inlineFuncDef+=feature.inlineFuncDef;
                globalVarDecl+=feature.globalVarDecl;
                globalVarDef+=feature.globalVarDef;
                globalStaticVarDef+=feature.globalStaticVarDef;
                templateTypeDecl+=feature.templateTypeDecl;
                templateTypeDef+=feature.templateTypeDef;
                templateFuncDecl+=feature.templateFuncDecl;
                templateFuncDef+=feature.templateFuncDef;
           }
           void FeatureDiv(int n){
                macroDefine/=n;
                typeDecl/=n;
                typeDef/=n;
                localSymbolDecl/=n;
                localSymbolDef/=n;
                typeNameDecl/=n;
                funcDecl/=n;
                funcDef/=n;
                staticFuncDecl/=n;
                staticFuncDef/=n;
                inlineFuncDecl/=n;
                inlineFuncDef/=n;
                globalVarDecl/=n;
                globalVarDef/=n;
                globalStaticVarDef/=n;
                templateTypeDecl/=n;
                templateTypeDef/=n;
                templateFuncDecl/=n;
                templateFuncDef/=n;
           }
           void FeatureMul(int n){
                macroDefine*=n;
                typeDecl*=n;
                typeDef*=n;
                localSymbolDecl*=n;
                localSymbolDef*=n;
                typeNameDecl*=n;
                funcDecl*=n;
                funcDef*=n;
                staticFuncDecl*=n;
                staticFuncDef*=n;
                inlineFuncDecl*=n;
                inlineFuncDef*=n;
                globalVarDecl*=n;
                globalVarDef*=n;
                globalStaticVarDef*=n;
                templateTypeDecl*=n;
                templateTypeDef*=n;
                templateFuncDecl*=n;
                templateFuncDef*=n;
           }
            void ShowOrExport(int total){
                string newFile=fileName;
                replace(newFile.begin(),newFile.end(),'/','_');
                //锁住当前文件
                myMutex.lock();

                Feature prevFeature(fid,fileName,fileType);
                int n=1;

                //判断文件是否存在
                ifstream inFile;
                inFile.open("info/"+newFile+".csv",ios::in);
                if(!inFile.is_open()){
                    n=0;
                    inFile.close();
                }
                //判断文件是否为空
                char c;
                inFile>>c;
                if(inFile.eof()){
                    n=0;
                    inFile.close();
                }
                inFile.close();

                if(n==1){
                    //读取之前fid总数和特征向量
                    ifstream readFile;
                    readFile.open("info/"+newFile+".csv",ios::in);
                    string line;
                    readFile>>line;
                    n=stoi(line);
                    readFile>>line;
                    readFile>>line;
                    vector<string> v=splitWithStl(line,",");
                    int vsize=v.size();
                    prevFeature.fid=stoi(v[0]);
                    prevFeature.fileName=v[1];
                    prevFeature.fileType=v[2];
                    prevFeature.macroDefine=stoi(v[3]);
                    prevFeature.typeDecl=stoi(v[4]);
                    prevFeature.localSymbolDecl=stoi(v[5]);
                    prevFeature.localSymbolDef=stoi(v[6]);
                    prevFeature.typeNameDecl=stoi(v[7]);
                    prevFeature.funcDecl=stoi(v[8]);
                    prevFeature.funcDef=stoi(v[9]);
                    prevFeature.staticFuncDecl=stoi(v[10]);
                    prevFeature.staticFuncDef=stoi(v[11]);
                    prevFeature.globalVarDecl=stoi(v[12]);
                    prevFeature.globalVarDef=stoi(v[13]);
                    prevFeature.globalStaticVarDef=stoi(v[14]);
                    prevFeature.templateTypeDecl=stoi(v[15]);
                    prevFeature.templateTypeDef=stoi(v[16]);
                    prevFeature.templateFuncDecl=stoi(v[17]);
                    prevFeature.templateFuncDef=stoi(v[18]);

                    prevFeature.FeatureMul(n);

                    readFile.close();
                }
                
                FeatureMul(total);
                FeatureAdd(prevFeature);
                n+=total;
                FeatureDiv(n);
                ofstream outFile;
                outFile.open("info/"+newFile+".csv",ios::out);

                //写入文件
                //写入文件fid总数
                outFile<<n<<endl;
                //写入表头
                outFile<<"fid"<<","<<"fileName"<<","<<"fileType"<<","<<"macroDefine"<<","<<"typeDecl"<<","
                <<"localSymbolDecl"<<","<<"localSymbolDef"<<","<<"typeNameDecl"<<","<<"funcDecl"<<","
                <<"funcDef"<<","<<"staticFuncDecl"<<","<<"staticFuncDef"<<","<<"globalVarDecl"<<","
                <<"globalVarDef"<<","<<"globalStaticVarDef"<<","<<"templateTypeDecl"<<","
                <<"templateTypeDef"<<","<<"templateFuncDecl"<<","<<"templateFuncDef"<<endl;
                //写入当前对象
                outFile<<fid<<","<<fileName<<","<<fileType<<","<<macroDefine<<","<<typeDecl<<","
                <<localSymbolDecl<<","<<localSymbolDef<<","<<typeNameDecl<<","<<funcDecl<<","
                <<funcDef<<","<<staticFuncDecl<<","<<staticFuncDef<<","<<globalVarDecl<<","
                <<globalVarDef<<","<<globalStaticVarDef<<","<<templateTypeDecl<<","
                <<templateTypeDef<<","<<templateFuncDecl<<","<<templateFuncDef<<endl;


                //关闭文件
                outFile.close();

                //释放锁
                myMutex.unlock();


                std::cout<<"--------------------------------------------------------------------------------------------------------------------------------------------------"<<"\n";
                std::cout<<fileName<<"\n";
                std::cout<<"\n";
                std::cout<<"fid:"<<fid<<"\n";
                std::cout<<"fileName:"<<fileName<<"\n";
                std::cout<<"fileType:."<<fileType<<"\n";
                std::cout<<"macroDefine:"<<macroDefine<<"\n";
                std::cout<<"typeDecl:"<<typeDecl<<"\n";
                std::cout<<"typeDef:"<<typeDef<<"\n";
                std::cout<<"localSymbolDecl:"<<localSymbolDecl<<"\n";
                std::cout<<"localSymbolDef:"<<localSymbolDef<<"\n";
                std::cout<<"typeNameDecl:"<<typeNameDecl<<"\n";
                std::cout<<"funcDecl:"<<funcDecl<<"\n";
                std::cout<<"funcDef:"<<funcDef<<"\n";
                std::cout<<"staticFuncDecl:"<<staticFuncDecl<<"\n";
                std::cout<<"staticFuncDef:"<<staticFuncDef<<"\n";
                std::cout<<"inlineFuncDecl:"<<inlineFuncDecl<<"\n";
                std::cout<<"inlineFuncDef:"<<inlineFuncDef<<"\n";
                std::cout<<"globalVarDecl:"<<globalVarDecl<<"\n";
                std::cout<<"globalVarDef:"<<globalVarDef<<"\n";
                std::cout<<"globalStaticVarDef:"<<globalStaticVarDef<<"\n";
                std::cout<<"templateTypeDecl:"<<templateTypeDecl<<"\n";
                std::cout<<"templateTypeDef:"<<templateTypeDef<<"\n";
                std::cout<<"templateFuncDecl:"<<templateFuncDecl<<"\n";
                std::cout<<"templateFuncDef:"<<templateFuncDef<<"\n";

            }
            
            unsigned int fid;
            string fileName;
            string fileType;
            unsigned int macroDefine;
            unsigned int typeDecl;
            unsigned int typeDef;
            unsigned int localSymbolDecl;
            unsigned int localSymbolDef;
            unsigned int typeNameDecl;
            unsigned int funcDecl;
            unsigned int funcDef;
            unsigned int staticFuncDecl;
            unsigned int staticFuncDef;
            unsigned int inlineFuncDecl;
            unsigned int inlineFuncDef;
            unsigned int globalVarDecl;
            unsigned int globalVarDef;
            unsigned int globalStaticVarDef;
            unsigned int templateTypeDecl;
            unsigned int templateTypeDef;
            unsigned int templateFuncDecl;
            unsigned int templateFuncDef;

    };
    class FileFeature{
        public:
        FileFeature(){
        }
        ~FileFeature(){
            featureMap.clear();
        }
        bool addFeature(unsigned int fid,Feature &feature){
            featureMap.emplace(fid,feature);   
            return true;
        }
        Feature &getFeature(unsigned int fid){
            return featureMap.at(fid);
        }
        bool isExist(unsigned int fid){
            if(featureMap.find(fid)==featureMap.end()){
                return false;
            }else{
                return true;
            }
        }
         //特征融合 取平均值
        void FeatureMix(){
            for (map<unsigned int,Feature>::iterator it=featureMap.begin(); it!=featureMap.end(); ++it){
              if(uniqueMap.find(it->second.fileName)==uniqueMap.end()){
                  uniqueMap.emplace(it->second.fileName,it->second);
                  total.emplace(it->second.fileName,1);
              }else{
                  uniqueMap.at(it->second.fileName).FeatureAdd(it->second);
                  total.at(it->second.fileName)++;
              }
           }
           for (auto it=uniqueMap.begin(); it!=uniqueMap.end(); ++it){
               it->second.FeatureDiv(total.at(it->first));
           }
           return;
        }

        void ShowOrExport(){
           FeatureMix();
           for (auto it=uniqueMap.begin(); it!=uniqueMap.end(); ++it){
               it->second.ShowOrExport(total.at(it->first));
           }
            return;
        }
        FileFeature& operator=(const FileFeature &feature){
            for(auto it=feature.featureMap.begin();it!=feature.featureMap.end();it++){
                featureMap.emplace(it->first,it->second);
            }
            return *this;
        }
        void clear(){
            featureMap.clear();
            uniqueMap.clear();
            total.clear();
        }
        private:
        //记录每个fid特征向量
        map<unsigned int,Feature> featureMap;
        //记录每个文件特征向量
        map<string,Feature> uniqueMap;
        //记录每个文件fid个数
        map<string,int>total;
    };
}
